#include "Plane.h"

#include "GL\glew.h"
#include "GL\freeglut.h"
#include <cmath>
#include <assert.h>
using std::vector;


Plane::Plane(int w, int l)
  : width(w), length(l)
{
} 
void Plane::init()
{
	assert(width < 1000);
	assert(length < 1000);

	vertices = vector<GLfloat> ( 3 * width*length,  0.0f );
  normals = vector<GLfloat> ( 3 * width*length,  0.0f );

  // Vertices & normals & texcoords:
  size_t vertIdx = 0;
  for(size_t z=0; z < length; z++)
  {
    for(size_t x=0; x<width; x++)
    {
      float middleX = ( float(width)-1.0f) / 2.0f;
      float middleZ = ( float(length)-1.0f) / 2.0f;
      vertices[vertIdx++] = float(x) - middleX;
      vertices[vertIdx++] = 0;
      vertices[vertIdx++] = float(z) - middleZ;

      //texCoords[texCoordIdx++] = (float) x / (width-1);
      //texCoords[texCoordIdx++] = (float) z / (length-1);
    }
  }
  // Eof vertices.

  // Mak indices
  size_t numIndices = (width*2) * (length - 1) + (length -2 );
  indices = vector<GLuint>( numIndices, 0);

  size_t index = 0;
  for(size_t z=0; z<length-1; z++)
  {
    if( z % 2 == 0)
    {
      size_t x;
      // Even row go left
      for(x=0; x<width; x++)
      {
        // column-major array ordering
        indices[index++] = x + (z * width); // bottom
        indices[index++] = x + ((z+1) * width); // top, 1 up Z-wise
      }

      // not last row? then make degenerate vert
      if( z < length-2)
      {
        indices[index++] = (--x) + (z * width); // negative X?
      }
    }
    else
    {
      size_t x;
      // Odd row go right
      for(x=width-1; x != -1; x--)
      {
        indices[index++] = x + (z * width); // bottom
        indices[index++] = x + ((z+1) * width); // top, 1 up Z-wise
      }

      // not last row? then make degenerate vert
      if( z < length-2)
      {
        // notice postinc of x value from -1 to 0.
        indices[index++] = ++x + (z * width);
      }
    }
  }


}
void Plane::render(double time)
{
  glEnable(GL_BLEND);
  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  glColor4f(0.0f,0.0f,0.8f,0.8f);

  float t = 10.0f * (float)time;

  //for(size_t i=0; i < indices.size(); i++)
  for(size_t x = 0; x < width; x++)
    for(size_t z = 0; z < length; z++)
  {
      float yofs = 0;
      yofs += 0.5f*sin( t + x/2.0f + z/2.0f);
      yofs += 1.0f*sin( t + x/16.0f + z/12.0f);
      yofs += 1.0f*sin( t + (x)/4.0f + z/8.0f);

      size_t vertIdx = 3*(x+z*width);
      //size_t vertIdx = 3 * indices[x + z*width];
      vertices[vertIdx+1]=yofs;
      // Calc vertex normal based on heightmap gradient
      float v0x = vertices[vertIdx+0]; float v0y = vertices[vertIdx+1]; float v0z = vertices[vertIdx+2];
      float v1x = vertices[vertIdx+0]+1; float v1y = vertices[vertIdx+1]; float v1z = vertices[vertIdx+2];
      float v2x = vertices[vertIdx+0]; float v2y = vertices[vertIdx+1]; float v2z = vertices[vertIdx+2]+1;

    if(x != width-1){
       size_t vertIdx = 3*((x+1)+z*width);
       v1y = vertices[vertIdx+1];
    }
    if(z != length-1){
      size_t vertIdx = 3*(x+(z+1)*width);
      v2y = vertices[vertIdx+1];
    }

      float e0x = v1x - v0x; float e0y = v1y - v0y; float e0z = v1z - v0z;
      float e1x = v2x - v0x; float e1y = v2y - v0y; float e1z = v2z - v0z;
      // Cross the two vectors e0 and e1
      // X=YZ-ZY <- :) "EX-yzy, its easy"
      // Y=ZX-XZ
      // Z=XY-YX
      float nx0 = e0y*e1z - e0z*e1y; float ny0 = e0z*e1y - e0x*e1z; float nz0 = e0x*e1x - e0y*e1x;
      // Normalize
      float len0 = sqrt(nx0*nx0 + ny0*ny0 + nz0*nz0);
      nx0 /= len0; ny0 /= len0; nz0 /= len0;
      // Compensating for multiplying with wrong handedness:
      normals[vertIdx+0] = -nx0;
      normals[vertIdx+1] = -ny0;
      normals[vertIdx+2] = -nz0;
  }

  glBindBuffer(GL_ARRAY_BUFFER, 0 );
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0 ); // <- IMPORTANT!!!

  //glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
  
  //glEnableClientState(GL_COLOR_ARRAY);
  glEnableClientState(GL_VERTEX_ARRAY);
  glEnableClientState(GL_NORMAL_ARRAY);
  //glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  

  //glColorPointer(3, GL_FLOAT, 0, colors);
  //glTexCoordPointer(2, GL_FLOAT, 0, &texCoords[0]);
  glNormalPointer(GL_FLOAT, 0 , &normals[0]);
  glVertexPointer(3, GL_FLOAT, 0 , &vertices[0]);

  //glDrawElements(	GL_TRIANGLE_STRIP, 
//	(width)*(length), 
//	GL_UNSIGNED_INT, 
//	&indices[0]);

    glDrawRangeElements(GL_TRIANGLE_STRIP,			// draw mode
      0, (width)*(length),		// minimum index, maximum index
      indices.size()	,							// number of primitives to draw
      GL_UNSIGNED_INT,							// indice datatype
      &indices[0] );								// indice array

    /*
    glDrawRangeElements(GL_TRIANGLE_STRIP,			// draw mode
      0, (3*(width)*(length))-1,				// minimum index, maximum index
      indices.size(),						// number of primitives to draw
      GL_UNSIGNED_INT,							// indice datatype
      &indices[0] );								// indice array
    */

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    //glDisableClientState(GL_COLOR_ARRAY);

    //glPopClientAttrib();

  //glPolygonMode(GL_FRONT, GL_FILL);
  glDisable(GL_BLEND);
}
